<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>卡片动画效果</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }

    body {
      background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 20px;
    }

    .container {
      max-width: 1200px;
      width: 100%;
      text-align: center;
    }

    h1 {
      color: white;
      font-size: 2.8rem;
      margin-bottom: 10px;
      text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    }

    .subtitle {
      color: rgba(255, 255, 255, 0.85);
      font-size: 1.2rem;
      margin-bottom: 40px;
      max-width: 600px;
      margin-left: auto;
      margin-right: auto;
    }

    .card-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
      gap: 30px;
      margin-top: 30px;
    }

    /* 卡片样式 */
    .card {
      background: rgba(255, 255, 255, 0.95);
      border-radius: 16px;
      overflow: hidden;
      box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
      transition: transform 0.3s ease;
      display: flex;
      flex-direction: column;
      height: 100%;
    }

    .card:hover {
      transform: translateY(-10px);
    }

    .card-header {
      background: linear-gradient(to right, #3494e6, #ec6ead);
      color: white;
      padding: 20px;
      text-align: center;
    }

    .card-title {
      font-size: 1.5rem;
      margin: 0;
    }

    .card-body {
      padding: 30px;
      flex-grow: 1;
      display: flex;
      flex-direction: column;
    }

    .card-content {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      min-height: 200px;
      overflow: hidden;
    }

    .card-main {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 5rem;
      color: #3494e6;
      background: rgba(52, 148, 230, 0.1);
      border-radius: 12px;
      padding: 20px;
    }

    .card-footer {
      padding: 20px;
      background: #f8f9fa;
      display: flex;
      justify-content: center;
      gap: 15px;
      flex-wrap: wrap;
    }

    /* 按钮样式 */
    .btn {
      padding: 12px 24px;
      border: none;
      border-radius: 50px;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.3s ease;
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .btn-info {
      background: linear-gradient(to right, #3494e6, #3aa9e9);
      color: white;
      box-shadow: 0 4px 15px rgba(52, 148, 230, 0.3);
    }

    .btn-info:hover {
      background: linear-gradient(to right, #2980b9, #3498db);
      transform: translateY(-2px);
      box-shadow: 0 6px 20px rgba(52, 148, 230, 0.4);
    }

    .btn-outline {
      background: transparent;
      border: 2px solid #3494e6;
      color: #3494e6;
    }

    .btn-outline:hover {
      background: rgba(52, 148, 230, 0.1);
    }

    /* 动画控制区域 */
    .controls {
      background: white;
      border-radius: 16px;
      padding: 30px;
      margin-top: 40px;
      box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
    }

    .control-title {
      color: #2c3e50;
      font-size: 1.8rem;
      margin-bottom: 20px;
    }

    .animation-selector {
      display: flex;
      justify-content: center;
      gap: 15px;
      flex-wrap: wrap;
      margin-top: 20px;
    }

    .animation-option {
      padding: 12px 25px;
      border-radius: 50px;
      background: #f1f4f8;
      cursor: pointer;
      transition: all 0.3s ease;
      font-weight: 500;
    }

    .animation-option:hover,
    .animation-option.active {
      background: linear-gradient(to right, #3494e6, #3aa9e9);
      color: white;
      box-shadow: 0 4px 15px rgba(52, 148, 230, 0.3);
    }

    /* 动画效果 */
    /* 淡入淡出 */
    .fade-enter-active,
    .fade-leave-active {
      transition: opacity 0.5s ease;
    }

    .fade-enter-from,
    .fade-leave-to {
      opacity: 0;
    }

    /* 缩放 */
    .scale-enter-active,
    .scale-leave-active {
      transition: all 0.5s ease;
    }

    .scale-enter-from,
    .scale-leave-to {
      opacity: 0;
      transform: scale(0.5);
    }

    /* 滑动 */
    .slide-enter-active,
    .slide-leave-active {
      transition: all 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55);
    }

    .slide-enter-from {
      opacity: 0;
      transform: translateX(-100%);
    }

    .slide-leave-to {
      opacity: 0;
      transform: translateX(100%);
    }

    /* 旋转 */
    .rotate-enter-active,
    .rotate-leave-active {
      transition: all 0.7s ease;
    }

    .rotate-enter-from {
      opacity: 0;
      transform: rotate(-90deg) scale(0.5);
    }

    .rotate-leave-to {
      opacity: 0;
      transform: rotate(90deg) scale(0.5);
    }

    /* 弹跳 */
    .bounce-enter-active {
      animation: bounce-in 0.7s;
    }

    .bounce-leave-active {
      animation: bounce-in 0.7s reverse;
    }

    @keyframes bounce-in {
      0% {
        transform: scale(0);
      }

      50% {
        transform: scale(1.1);
      }

      100% {
        transform: scale(1);
      }
    }

    /* 说明文本 */
    /* 作用对象：元素背后的内容（背景）
      效果：对元素后方的内容进行模糊处理，常用于创建毛玻璃效果
      兼容性：现代浏览器支持（需无前缀），Safari需要-webkit-前缀
      典型应用场景：导航栏、侧边栏等需要背景模糊的覆盖层
      -webkit-backdrop-filter: blur(10px)
      与标准版的唯一区别：带-webkit-前缀的旧版语法
      兼容性：主要用于Safari 9+等WebKit内核浏览器
      注意：现代浏览器已支持无前缀版本，建议同时使用两者保证兼容性
      filter: blur(10px)
      作用对象：元素自身及其所有子内容
      效果：对整个元素（包括内容）进行模糊处理
      兼容性：所有现代浏览器支持
      典型应用场景：图片模糊处理、加载状态模糊效果 */
    .instructions {
      background: rgba(255, 255, 255, 0.2);
      /* backdrop-filter: blur(10px); */
      --webkit-backdrop-filter: blur(10px);
      filter: blur(10px);
      border-radius: 12px;
      padding: 20px;
      margin-top: 30px;
      color: white;
      max-width: 800px;
      margin-left: auto;
      margin-right: auto;
    }

    .instructions h3 {
      margin-bottom: 15px;
      display: flex;
      align-items: center;
      gap: 10px;
      justify-content: center;
    }

    .instructions p {
      line-height: 1.6;
      margin-bottom: 15px;
    }

    .highlight {
      background: rgba(255, 255, 255, 0.3);
      padding: 2px 8px;
      border-radius: 4px;
      font-weight: 500;
    }

    @media (max-width: 768px) {
      .card-grid {
        grid-template-columns: 1fr;
      }

      h1 {
        font-size: 2.2rem;
      }
    }
  </style>
</head>

<body>
  <div id="app">
    <div class="container">
      <h1><i class="fas fa-magic"></i> Vue 3 卡片动画效果</h1>
      <p class="subtitle">点击卡片中的按钮体验不同的动画效果，或使用下方控制面板选择动画类型</p>

      <div class="card-grid">
        <!-- 卡片1 -->
        <div class="card">
          <div class="card-header">
            <h2 class="card-title">淡入淡出效果</h2>
          </div>
          <div class="card-body">
            <div class="card-content">
              <transition :name="selectedAnimation === 'fade' ? 'fade' : ''">
                <div v-if="showCardContent" class="card-main">
                  <i class="fas fa-star"></i>
                </div>
              </transition>
            </div>
          </div>
          <div class="card-footer">
            <button class="btn btn-info" @click="toggleCardContent">
              <i class="fas fa-play"></i> {{ showCardContent ? '隐藏内容' : '显示内容' }}
            </button>
          </div>
        </div>

        <!-- 卡片2 -->
        <div class="card">
          <div class="card-header">
            <h2 class="card-title">缩放效果</h2>
          </div>
          <div class="card-body">
            <div class="card-content">
              <transition :name="selectedAnimation === 'scale' ? 'scale' : ''">
                <div v-if="showCardContent" class="card-main">
                  <i class="fas fa-heart"></i>
                </div>
              </transition>
            </div>
          </div>
          <div class="card-footer">
            <button class="btn btn-info" @click="toggleCardContent">
              <i class="fas fa-play"></i> {{ showCardContent ? '隐藏内容' : '显示内容' }}
            </button>
          </div>
        </div>
      </div>

      <!-- 控制面板 -->
      <div class="controls">
        <h2 class="control-title">选择动画效果</h2>
        <div class="animation-selector">
          <div v-for="(anim, index) in animations" :key="index" class="animation-option"
            :class="{ active: selectedAnimation === anim.value }" @click="selectAnimation(anim.value)">
            <i :class="anim.icon"></i> {{ anim.name }}
          </div>
        </div>
      </div>

      <!-- 说明 -->
      <div class="instructions">
        <h3><i class="fas fa-lightbulb"></i> 实现说明</h3>
        <p>此示例使用Vue 3的<strong>Transition组件</strong>实现动画效果。通过动态绑定<strong
            class="highlight">:name</strong>属性，我们可以切换不同的动画效果。</p>
        <p>核心代码：</p>
        <p><strong>1. 使用v-if控制元素显示/隐藏</strong> - 通过响应式变量showCardContent控制内容区域的显示状态</p>
        <p><strong>2. 绑定动态动画名称</strong> - 根据用户选择绑定不同的动画效果名称</p>
        <p><strong>3. CSS动画定义</strong> - 为每种动画效果编写对应的CSS过渡类</p>
      </div>
    </div>
  </div>

  <script>
    const { createApp, ref } = Vue;

    createApp({
      setup() {
        const showCardContent = ref(true);
        const selectedAnimation = ref('fade');

        const animations = [
          { name: '淡入淡出', value: 'fade', icon: 'fas fa-bahai' },
          { name: '缩放效果', value: 'scale', icon: 'fas fa-expand' },
          { name: '滑动效果', value: 'slide', icon: 'fas fa-arrows-alt-h' },
          { name: '旋转效果', value: 'rotate', icon: 'fas fa-sync' },
          { name: '弹跳效果', value: 'bounce', icon: 'fas fa-volleyball-ball' }
        ];

        const toggleCardContent = () => {
          showCardContent.value = !showCardContent.value;
        };

        const selectAnimation = (anim) => {
          selectedAnimation.value = anim;
          showCardContent.value = false;
          setTimeout(() => {
            showCardContent.value = true;
          }, 50);
        };

        return {
          showCardContent,
          selectedAnimation,
          animations,
          toggleCardContent,
          selectAnimation
        };
      }
    }).mount('#app');
  </script>
</body>

</html>